﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CoreUtils.WIL
{
    /// <summary>
    /// Transformation functions from WIL library
    /// </summary>
    public class Transform
    {
        public static FVIL.Data.CFviImage affine(FVIL.Data.CFviImage src, double degree)
        {
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            FVIL.GeoTrans.CFviAffine parser = new FVIL.GeoTrans.CFviAffine();
            parser.SrcImages[0] = src;
            parser.DstImages[0] = dst;
            {
                FVIL.Data.CFviAngle angle = new FVIL.Data.CFviAngle(degree);
                FVIL.Data.CFviRectangle clip = new FVIL.Data.CFviRectangle(0, 0, src.Window.Width, src.Window.Height);
                clip.Angle = angle;
                FVIL.Data.CFviPolyline vertex = clip.ToCFviPolyline();
                FVIL.Data.CFviPoint st = vertex[0];
                FVIL.Data.CFviPoint ed = vertex[0];
                for (int i = 0; i < vertex.Count; i++)
                {
                    if (st.X > vertex[i].X) st.X = vertex[i].X;
                    if (st.Y > vertex[i].Y) st.Y = vertex[i].Y;
                    if (ed.X < vertex[i].X) ed.X = vertex[i].X;
                    if (ed.Y < vertex[i].Y) ed.Y = vertex[i].Y;
                }
                int horz = (int)(Math.Abs(ed.X - st.X) + 0.9);
                int vert = (int)(Math.Abs(ed.Y - st.Y) + 0.9);
                double R = angle.Radian;
                double em11 = +Math.Cos(R);
                double em12 = -Math.Sin(R);
                double em21 = +Math.Sin(R);
                double em22 = +Math.Cos(R);
                double axis_x = -0.5;
                double axis_y = -0.5;
                FVIL.Data.CFviMatrix mr = new FVIL.Data.CFviMatrix(3, 3);
                mr[0, 0] = +Math.Cos(R); mr[0, 1] = -Math.Sin(R); mr[0, 2] = 0.0;
                mr[1, 0] = +Math.Sin(R); mr[1, 1] = +Math.Cos(R); mr[1, 2] = 0.0;
                mr[2, 0] = 0.0; mr[2, 1] = 0.0; mr[2, 2] = 1.0;
                FVIL.Data.CFviMatrix ms = new FVIL.Data.CFviMatrix(3, 3);
                ms[0, 0] = 1.0; ms[0, 1] = 0.0; ms[0, 2] = Math.Abs(Math.Min(st.X, 0.0));
                ms[1, 0] = 0.0; ms[1, 1] = 1.0; ms[1, 2] = Math.Abs(Math.Min(st.Y, 0.0));
                ms[2, 0] = 0.0; ms[2, 1] = 0.0; ms[2, 2] = 1.0;
                FVIL.Data.CFviMatrix mp = new FVIL.Data.CFviMatrix(3, 3);
                mp[0, 0] = 1.0; mp[0, 1] = 0.0; mp[0, 2] = (axis_x - axis_x * em11 - axis_y * em12);
                mp[1, 0] = 0.0; mp[1, 1] = 1.0; mp[1, 2] = (axis_y - axis_x * em21 - axis_y * em22);
                mp[2, 0] = 0.0; mp[2, 1] = 0.0; mp[2, 2] = 1.0;
                FVIL.Data.CFviMatrix mm = mp * ms * mr;
                parser.Matrix.CopyFrom(mm);
            }
            parser.Validate(1);
            parser.Execute();
            return dst;
        }

        public static FVIL.Data.CFviImage mirror(FVIL.Data.CFviImage src)
        {
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            FVIL.GeoTrans.CFviMirror parser = new FVIL.GeoTrans.CFviMirror();
            parser.SrcImages[0] = src;
            parser.DstImages[0] = dst;
            parser.Validate();
            parser.Direction = FVIL.GeoTrans.MirrorDirection.XDirection;
            parser.Execute();
            return dst;
        }

        public static FVIL.Data.CFviImage perspective(FVIL.Data.CFviImage src)
        {
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            FVIL.Data.CFviImage mask = new FVIL.Data.CFviImage();
            FVIL.GeoTrans.CFviPerspective parser = new FVIL.GeoTrans.CFviPerspective();
            parser.SrcImages[0] = src;
            parser.DstImages[0] = dst;
            parser.DstImages[1] = mask;
            FVIL.Data.CFviMatrix ms = parser.Matrix;
            ms[0, 0] = 0.501961; ms[0, 1] = -0.335079; ms[0, 2] = 64.000000;
            ms[1, 0] = -0.000000; ms[1, 1] = 0.250652; ms[1, 2] = 48.000000;
            ms[2, 0] = -0.000000; ms[2, 1] = -0.002608; ms[2, 2] = 1.000000;
            dst.SetSize(src.HorzSize, src.VertSize, src.ImageType, src.Channel);
            mask.SetSize(src.HorzSize, src.VertSize, FVIL.ImageType.BIN, src.Channel);
            parser.Execute();
            return dst;
        }

        public static FVIL.Data.CFviImage rotate(FVIL.Data.CFviImage src, double axis,
            double angle)
        {
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            FVIL.Data.CFviImage mask = new FVIL.Data.CFviImage();
            FVIL.GeoTrans.CFviRotate parser = new FVIL.GeoTrans.CFviRotate();
            parser.SrcImages[0] = src;
            parser.DstImages[0] = dst;
            parser.DstImages[1] = mask;
            parser.Axis = new FVIL.Data.CFviPoint(src.HorzSize * axis, src.VertSize * axis);
            parser.Angle = new FVIL.Data.CFviAngle(angle);
            parser.SamplingMode = FVIL.GeoTrans.SamplingMode.Super;
            parser.ClearBackMode = true;
            src.Window = new System.Drawing.Rectangle(0, 0, (int)parser.Axis.X, (int)parser.Axis.Y);
            dst.SetSize(src.HorzSize, src.VertSize, src.ImageType, src.Channel);
            mask.SetSize(src.HorzSize, src.VertSize, FVIL.ImageType.BIN, src.Channel);
            parser.Execute();
            return dst;
        }

        public static FVIL.Data.CFviImage scale(FVIL.Data.CFviImage src, double magHorz,
            double magVert)
        {
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            FVIL.GeoTrans.CFviScale parser = new FVIL.GeoTrans.CFviScale();
            parser.SrcImages[0] = src;
            parser.DstImages[0] = dst;
            parser.MagnificationOfHorz = magHorz;
            parser.MagnificationOfVert = magVert;
            parser.SamplingMode = FVIL.GeoTrans.SamplingMode.Cubic;
            parser.ClearBackMode = true;

            int horz = (int)(src.HorzSize * parser.MagnificationOfHorz);
            int vert = (int)(src.VertSize * parser.MagnificationOfVert);
            dst.SetSize(horz, vert, src.ImageType, src.Channel);
            parser.Execute();
            return dst;
        }

        public static FVIL.Data.CFviImage shift(FVIL.Data.CFviImage src, double rateHorz,
            double rateVert)
        {
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            FVIL.Data.CFviImage mask = new FVIL.Data.CFviImage();
            FVIL.GeoTrans.CFviShift parser = new FVIL.GeoTrans.CFviShift();
            parser.SrcImages[0] = src;
            parser.DstImages[0] = dst;
            parser.DstImages[1] = mask;
            parser.ShiftX = src.HorzSize * rateHorz;
            parser.ShiftY = src.VertSize * rateVert;
            parser.SamplingMode = FVIL.GeoTrans.SamplingMode.Bilinear;
            parser.ClearBackMode = true;
            dst.SetSize(src.HorzSize, src.VertSize, src.ImageType, src.Channel);
            mask.SetSize(src.HorzSize, src.VertSize, FVIL.ImageType.BIN, src.Channel);
            parser.Execute();
            return dst;
        }

        public static FVIL.Data.CFviImage transpose(FVIL.Data.CFviImage src)
        {
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            FVIL.GeoTrans.CFviTranspose parser = new FVIL.GeoTrans.CFviTranspose();
            parser.SrcImages[0] = src;
            parser.DstImages[0] = dst;
            parser.Validate();
            parser.Execute();
            return dst;
        }

        public static FVIL.Data.CFviImage polarTransform(FVIL.Data.CFviImage src,
            double stAngle, double edAngle)
        {
            FVIL.PolarTrans.CFviPolarTrans parser = new FVIL.PolarTrans.CFviPolarTrans();
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            int valid = FVIL.PolarTrans.CFviPolarTrans.CheckValidity(src);
            if (valid != FVIL.ErrorCode._SUCCESS)
                throw new FVIL.CFviException(valid, "FVIL.PolarTrans.CFviPolarTrans.CheckValidity");
            parser.SrcImages[0] = src;
            parser.DstImages[0] = dst;

            parser.Invert = false;
            parser.ClearBackMode = true;
            parser.SamplingMode = FVIL.PolarTrans.SamplingMode.Bilinear;
            parser.Param.CoordinateMode = FVIL.PolarTrans.CoordinateMode.Left;

            FVIL.PolarTrans.CFviPolarTransParam param = parser.Param;
            param.CoordinateMode = FVIL.PolarTrans.CoordinateMode.Left;
            param.OriginIn = new FVIL.Data.CFviPoint(src.Window.X, src.Window.Y);
            param.Width = src.Window.Width;
            param.Height = src.Window.Height;
            param.OriginOut = new FVIL.Data.CFviPoint(param.Width, param.Width);
            param.Radius = param.Width;
            param.StartAngle = new FVIL.Data.CFviAngle(stAngle);
            param.RangeAngle = new FVIL.Data.CFviAngle(edAngle);
            parser.Validate(1);
            parser.Execute();
            return dst;
        }

    }
}
